package com.qd.panda.service.third.etc;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import com.cdqidi.exception.ApiException;
import com.cdqidi.httpclientbootstart.util.HttpUtil;
import com.cdqidi.util.DateUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.qd.panda.service.third.etc.dto.RespDTO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class EtcApiService {
    @Value("${etc.account_no}")
    private String accountNo;
    @Value("${etc.password}")
    private String password;
    @Value("${etc.app_code}")
    private String appCode;
    @Value("${etc.bank_code}")
    private String bankCode;
    @Value("${etc.org_code}")
    private String orgCode;
    @Value("${etc.org_code_num}")
    private String orgCodeNum;
    @Value("${etc.domain}")
    private String domain;

    private static final String LOGIN_URL = "/etc-api/account/Login";
    private static final String LOGOUT_URL = "/etc-api/account/Logout";
    private static final String NAVIGATE_INIT_URL = "/etc-api/wechat/navigateinit";
    private static final String ETC_API_LOGIN_KEY = "etc_api_login_key";
    private static final String NAVIGATE_INIT_KEY = "navigateinit";
    private final ObjectMapper objectMapper;
    private final HttpUtil httpUtil;
    private final StringRedisTemplate stringRedisTemplate;


    /**
     * 登录
     *
     * @return 返回秘钥
     */
    @SneakyThrows
    public String login() {
        String sessionKey = stringRedisTemplate.opsForValue().get(ETC_API_LOGIN_KEY);
        if (StringUtils.hasLength(sessionKey)) {
            return sessionKey;
        }
        ObjectNode objectNode = objectMapper.createObjectNode();
        objectNode.put("AccountNo", EtcSignUtil.getRsa().encryptBase64(accountNo, KeyType.PublicKey));
        objectNode.put("Password", SecureUtil.md5(password).toUpperCase());
        String reqJsonStr = EtcSignUtil.createReqJsonStr(objectNode, orgCode);
        log.info("login request url: {},param: {}", domain + LOGIN_URL, reqJsonStr);
        String responseJsonStr = httpUtil.sendPostNotKeepAlive(domain + LOGIN_URL, reqJsonStr);
        log.info("login response: {}", responseJsonStr);
        boolean sign = EtcSignUtil.isSign(responseJsonStr);
        log.info("response sign: {}", sign);
        RespDTO respDTO = objectMapper.readValue(responseJsonStr, RespDTO.class);
        if (respDTO.getSuccess()) {
            checkResp(respDTO.getBizContent());
            sessionKey = EtcSignUtil.getRsa().decryptStr(respDTO.getBizContent().get("SessionKey").asText(), KeyType.PrivateKey);
            stringRedisTemplate.opsForValue().set(ETC_API_LOGIN_KEY, sessionKey, 1, TimeUnit.HOURS);
            return sessionKey;
        }
        throw new ApiException(respDTO.getMsg());
    }

    /**
     * 退出登录
     */
    @SneakyThrows
    public void logout() {
        ObjectNode objectNode = objectMapper.createObjectNode();
        objectNode.put("AccountNo", EtcSignUtil.getRsa().encryptBase64(accountNo, KeyType.PublicKey));
        objectNode.put("Password", SecureUtil.md5(password).toUpperCase());
        String reqJsonStr = EtcSignUtil.createReqJsonStr(objectNode, orgCode);
        log.info("logout request url: {},param: {}", domain + LOGOUT_URL, reqJsonStr);
        String response = httpUtil.sendPostNotKeepAlive(domain + LOGOUT_URL, reqJsonStr);
        log.info("logout response: {}", response);
        RespDTO respDTO = objectMapper.readValue(response, RespDTO.class);
        if (respDTO.getSuccess()) {
            stringRedisTemplate.delete(ETC_API_LOGIN_KEY);
            log.info("退出登录成功");
            checkResp(respDTO.getBizContent());
        } else {
            log.error("退出登录失败,errMsg: {}", respDTO.getMsg());
        }
    }

    /**
     * 合作机构小程序跳转小程序接口初始化
     *
     * @return
     */
    @SneakyThrows
    public JsonNode navigateInit() {
        String respStr = stringRedisTemplate.opsForValue().get(NAVIGATE_INIT_KEY);
        if (StringUtils.hasLength(respStr)) {
            return objectMapper.readTree(respStr);
        } else {
            String sessionKey = login();
            ObjectNode objectNode = objectMapper.createObjectNode();
            ObjectNode childNode = objectMapper.createObjectNode();
            childNode.put("msg_id", createMsgId());
            childNode.put("App_code", appCode);
            childNode.put("bank_code", bankCode);

            objectNode.put("ReqData", EtcSignUtil.aes(sessionKey, childNode.toString()));
            String reqJsonStr = EtcSignUtil.createReqJsonStr(objectNode, orgCode);
            log.info("navigateInit request url: {},param: {}", domain + NAVIGATE_INIT_URL, reqJsonStr);
            String response = httpUtil.sendPostNotKeepAlive(domain + NAVIGATE_INIT_URL, reqJsonStr);
            log.info("navigateInit response: {}", response);
            RespDTO respDTO = objectMapper.readValue(response, RespDTO.class);
            if (respDTO.getSuccess()) {
                checkResp(respDTO.getBizContent());
                JsonNode resDataJsonNode = respDTO.getBizContent().get("ResData");
                log.info("navigateInit,ResData: {}", resDataJsonNode);
                String resData = EtcSignUtil.des(sessionKey, resDataJsonNode.asText());
                log.info("解密后的resData: {}", resData);
                JsonNode jsonNode = objectMapper.readTree(resData);
                stringRedisTemplate.opsForValue().set(NAVIGATE_INIT_KEY, jsonNode.toString(), 1, TimeUnit.HOURS);
                return jsonNode;
            } else {
                log.error("合作机构小程序跳转小程序接口初始化,errMsg: {}", respDTO.getMsg());
                throw new ApiException(respDTO.getMsg());
            }
        }

    }

    public void checkResp(JsonNode jsonNode) {
        String rFlag = jsonNode.get("RFlag").asText();
        if (rFlag.equals("1")) {
            throw new ApiException(jsonNode.get("RMess").asText());
        }
    }

    public String createMsgId() {
        return orgCodeNum + DateUtil.getStringDate(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(3);
    }
}